package MyGui;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JComboBox;
import java.util.Vector;

import DistSys.Sys;
import DistSys.Zone;
import Element.Geom.AbsElemGeom;

/**
 * The class <code>ZoneComboBox</code> implements a combo box for zone
 * selection.
 *
 */
public class ZoneComboBox extends JComboBox implements FocusListener {
    boolean bIncludeSpecialZones = true;

    /**
     * Constructs a <code>ZoneComboBox</code> including the special zones but
     * with no preselected zone.
     */
    public ZoneComboBox() {
        this(true);
    }

    /**
     * Constructs a <code>ZoneComboBox</code> with no preselected zone.
     *
     * @param  includeSpecialZones  a boolean specifying whether the special
     *                              zones should be included.
     */
    public ZoneComboBox(boolean includeSpecialZones) {
        super();

        bIncludeSpecialZones = includeSpecialZones;
        setEditable(true);
        getEditor().getEditorComponent().addFocusListener(this);

        if (bIncludeSpecialZones) {
            setSelectedItem(Zone.getZoneString(Zone.ENTIRE_SYSTEM));
        }
    }

    /**
     * Constructs a <code>ZoneComboBox</code> including the special zones and
     * with a preselected zone.
     *
     * @param   zone   the zone to be preselected
     */
    public ZoneComboBox(Object zone) {
        this(true);

        if (zone instanceof Zone) {
            setSelectedItem(((Zone)zone).getZoneString());
        } else if (zone instanceof Double) {
            setSelectedItem(Zone.getZoneString(((Double)zone).doubleValue()));
        } else if (zone instanceof Integer) {
            setSelectedItem(Zone.getZoneString(
                (double)((Integer)zone).intValue()));
        } else
            setSelectedItem(zone);
    }

    /**
     * This method is public as an implementation side effect.
     * do not call or override.
     */
    public void focusGained(FocusEvent e) {
        // save currently selected zone string
        Object savedZone = getSelectedItem();

        // remove all previous zones
        removeAllItems();

        // add special zones if wanted
        if (bIncludeSpecialZones) {
            addItem(Zone.getZoneString(Zone.ENTIRE_SYSTEM));
            addItem(Zone.getZoneString(Zone.STUDY_AREA));
            addItem(Zone.getZoneString(Zone.SELECTED_AREA));
        }

        // add normal zones
        for (int i = 0; i < Sys.prjInfo.allZone.size(); i++)
            addItem(((Zone)Sys.prjInfo.allZone.elementAt(i)).getZoneString());

        // restore zone if possible
        if (savedZone != null)
            setSelectedItem(savedZone);
    }

    /**
     * This method is public as an implementation side effect.
     * do not call or override.
     */
     public void focusLost(FocusEvent e) { }

    /**
     * Retrieves the current selected zone.
     *
     * @exception ZoneException if the current zone is invalid.
     *
     * @see     MyGui.ZoneComboBox.ZoneException
     */
    public double getSelectedZone() throws ZoneException {
        String choice = (String)getSelectedItem();
        if (choice == null) {
            // There is no selection so let us throw an exception.
            throw new ZoneException("");
        }

        // search for choice in the special zones
        if (choice.equals(Zone.getZoneString(Zone.ENTIRE_SYSTEM)))
            return Zone.ENTIRE_SYSTEM;
        if (choice.equals(Zone.getZoneString(Zone.STUDY_AREA)))
            return Zone.STUDY_AREA;
        if (choice.equals(Zone.getZoneString(Zone.SELECTED_AREA)))
            return Zone.SELECTED_AREA;

        // search for choice in zone labels and zone strings
        for (int i = 0; i < Sys.prjInfo.allZone.size(); i++) {
            Zone z = (Zone)Sys.prjInfo.allZone.elementAt(i);
            if (choice.equals(z.getZoneString()) ||
                choice.equals(z.getZoneLabel())) {
                return z.getZoneNumber();
            }
        }

        // search for choice as pure zone number
        try {
            double dZone = Double.parseDouble(choice);
            for (int i = 0; i < Sys.prjInfo.allZone.size(); i++) {
                Zone z = (Zone)Sys.prjInfo.allZone.elementAt(i);
                if (z.getZoneNumber() == dZone) {
                    return z.getZoneNumber();
                }
            }
        } catch(NumberFormatException e) {
            // Error will be handled later
        }
        // We haven't found a valid zone (for whatever reason)
        // so let us throw an exception.
        throw new ZoneException(choice);
    }

    /**
     * Sets the selected zone in the <code>ZoneComboBox</code> by
     * specifying the zone index.
     *
     * @param dZone  the zone to select
     */
    public void setSelectedZone(double dZone) {
        setSelectedItem(Zone.getZoneString(dZone));
    }

    /**
     * The class <code>ZoneException</code> indicates that an illegal zone was
     * found.
     *
     * @see     MyGui.ZoneComboBox#getSelectedZone
     */
    public class ZoneException extends Exception {
        /**
         * Constructs a <code>ZoneException</code> with no specified zone string.
         */
        public ZoneException() {}

        /**
         * Constructs a <code>ZoneException</code> with the specified zone string.
         *
         * @param   zone   the zone string.
         */
        public ZoneException(String zone) {
            super(zone);
        }
    };
}
